package com.ruoyi.demo.dao.impl;

import com.alibaba.fastjson2.JSON;
import com.ruoyi.demo.dao.HotelDocDao;
import com.ruoyi.demo.pojo.doc.HotelDoc;
import com.ruoyi.demo.pojo.dto.PageResult;
import com.ruoyi.demo.pojo.vo.HotelSearchFormVO;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Repository
public class HotelDocDaoImpl implements HotelDocDao {
    private final RequestOptions options=RequestOptions.DEFAULT;
    private static final String indexName="hotel";
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    public PageResult<HotelDoc> search(HotelSearchFormVO formVO) {
        SearchRequest request=new SearchRequest("hotel");
        SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
        BoolQueryBuilder boolQuery= QueryBuilders.boolQuery();

        if (formVO.getKeyword() != null && !formVO.getKeyword().isEmpty()){
            boolQuery.must(QueryBuilders.matchQuery("searchInfo",formVO.getKeyword()));
        }

        if (formVO.getBrand() != null && !formVO.getBrand().isEmpty()){
            boolQuery.filter(QueryBuilders.matchQuery("brand",formVO.getBrand()));
        }
        if (formVO.getCity() != null && !formVO.getCity().isEmpty()){
            boolQuery.filter(QueryBuilders.matchQuery("city",formVO.getCity()));
        }
        if (formVO.getMinScore() != null){
            boolQuery.filter(QueryBuilders.matchQuery("score",formVO.getMinScore()));
        }
        if (formVO.getMaxStar() != null){
            boolQuery.filter(QueryBuilders.matchQuery("star",formVO.getMaxStar()));
        }
        if (formVO.getMinPrice() != null){
            boolQuery.filter(QueryBuilders.matchQuery("price",formVO.getMinPrice()));
        }
        if (formVO.getMaxPrice() != null){
            boolQuery.filter(QueryBuilders.matchQuery("price",formVO.getMaxPrice()));
        }

        searchSourceBuilder.query(boolQuery);

        int page=formVO.getPage()==null ? 1 : formVO.getPage();
        int size=formVO.getSize()==null ? 10 : formVO.getSize();
        searchSourceBuilder.from((page-1)*size);
        searchSourceBuilder.size(size);

        String sortBy=formVO.getSortBy();
        if (sortBy!=null && !sortBy.isEmpty()){
            String[] sortArr=sortBy.split(",");
            for (String sortStr:sortArr){
                switch (sortStr){
                    case "price":
                        if (formVO.getSortByPrice() !=null && !formVO.getSortByPrice().isEmpty()){
                            searchSourceBuilder.sort(sortStr, SortOrder.fromString(formVO.getSortByPrice()));
                        }
                        break;
                    case "score":
                        if (formVO.getSortByScore() !=null && !formVO.getSortByScore().isEmpty()){
                            searchSourceBuilder.sort(sortStr, SortOrder.fromString(formVO.getSortByScore()));
                        }
                        break;
                    case "star":
                        if (formVO.getSortByStar() !=null && !formVO.getSortByStar().isEmpty()){
                            searchSourceBuilder.sort(sortStr, SortOrder.fromString(formVO.getSortByStar()));
                        }
                        break;
                }
            }
        }

        request.source(searchSourceBuilder);

        SearchResponse searchResponse=null;
        try {
            searchResponse=restHighLevelClient.search(request,RequestOptions.DEFAULT);

            List<HotelDoc> hotelDocs=new ArrayList<>();
            for (SearchHit hit:searchResponse.getHits().getHits()){
                String json=hit.getSourceAsString();
                HotelDoc hotelDoc=JSON.parseObject(json,HotelDoc.class);
                hotelDocs.add(hotelDoc);
            }

            PageResult<HotelDoc> pageResult=new PageResult<>();
            pageResult.setTotal(searchResponse.getHits().getTotalHits().value);
            pageResult.setList(hotelDocs);
            return pageResult;
        }catch (IOException e){
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public boolean insert(HotelDoc hotelDoc) {
        try {
            IndexRequest request=new IndexRequest(indexName,"_doc").id(hotelDoc.getId()).source(JSON.toJSONString(hotelDoc), XContentType.JSON);
            this.restHighLevelClient.index(request,options);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public HotelDoc getById(String id) {
        try {
            GetRequest request=new GetRequest(indexName,id);
            String json=this.restHighLevelClient.get(request,options).getSourceAsString();
            return JSON.parseObject(json,HotelDoc.class);
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public boolean update(HotelDoc hotelDoc) {
        try {
            UpdateRequest request=new UpdateRequest(indexName,hotelDoc.getId()).doc(JSON.toJSONString(hotelDoc), XContentType.JSON);
            this.restHighLevelClient.update(request,options);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public boolean delete(String id) {
        try {
            DeleteRequest request=new DeleteRequest(indexName,id);
            this.restHighLevelClient.delete(request,options);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}
